#include <CODEPORTS/codeports.h>
#include "codeports.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

void
MIC_Init(void)
{
	unsigned int i;

	if((snd_pcm_open(&audio.microphone, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0)
	{
		perror("Error: Unable to open default alsa capture device");
		exit (1);
	}

	if((snd_pcm_hw_params_malloc(&audio.mode.microphone.current)) < 0)
	{
		perror("Eror: Unable to allocate microphone hardware parameter structure");
		exit (1);
	}
			 
	if((snd_pcm_hw_params_any(audio.microphone, audio.mode.microphone.current)) < 0)
	{
		perror("Eror: Unable to initialize microphone hardware parameter structure");
		exit (1);
	}

	if((snd_pcm_hw_params_set_access(audio.microphone, audio.mode.microphone.current, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
	{
		perror("Eror: Unable to set microphone access type");
		exit (1);
	}

	printf("Microphone Modes:\n");
	for(i = 0; i < sizeof(microphone_modes) / sizeof(AUDIO_MODE); i++)
		printf("\t%i: %dx%d, %dbps\n", i, microphone_modes[i].channels, microphone_modes[i].rate, microphone_modes[i].bytes_per_sample);
	printf("Microphone Mode: ");
	scanf("%i", &audio.mode.microphone.code);
	getchar();

	if(audio.mode.microphone.code == audio.mode.microphone.code)
	{
		audio.mode.microphone.rate = microphone_modes[audio.mode.microphone.code].rate;
		audio.mode.microphone.channels = microphone_modes[audio.mode.microphone.code].channels;
		audio.mode.microphone.bytes_per_sample = microphone_modes[audio.mode.microphone.code].bytes_per_sample;
		audio.mode.microphone.direction = 0; //microphone_modes[audio.mode.microphone.code].direction;

		//! if((snd_pcm_hw_params_set_format(audio.microphone, audio.mode.microphone.current, audio.mode.microphone.current.bytes_per_sample)) < 0)
		if((snd_pcm_hw_params_set_format(audio.microphone, audio.mode.microphone.current, SND_PCM_FORMAT_S16_LE)) < 0)
		{
			perror("Eror: Unable to set microphone format");
			exit(1);
		}

		if((snd_pcm_hw_params_set_rate_near(audio.microphone, audio.mode.microphone.current, &audio.mode.microphone.rate, &audio.mode.microphone.direction)) < 0)
		{
			perror("Eror: Unable to set microphone rate");
			exit(1);
		}

		if((snd_pcm_hw_params_set_channels(audio.microphone, audio.mode.microphone.current, audio.mode.microphone.channels)) < 0)
		{
			perror("Eror: Unable to set microphone channels");
			exit(1);
		}
	}

	if((snd_pcm_hw_params(audio.microphone, audio.mode.microphone.current)) < 0)
	{
		perror("Eror: Unable to set microphone parameters");
		exit(1);
	}

	if((snd_pcm_prepare(audio.microphone)) < 0)
	{
		perror("Eror: Unable to prepare microphone");
		exit(1);
	}

	/*
	switch(cp.video.mode.current.bits_per_pixel >> 3)
	{
		case 1:
		{
			SCR_SetPaletteRGB();
			SCR_SetPixelRGB = SCR_SetPixelRGB8;
			SCR_GetPixelRGB = SCR_GetPixelRGB8;
			SCR_SetBoxRGB = SCR_SetBoxRGB8;
			SCR_SetBox = SCR_SetBoxRGB8;
			BOX_SetPixelRGB = BOX_SetPixelRGB8;
			BOX_GetPixelRGB = BOX_GetPixelRGB8;
			break;
		}
		case 2:
		{
			SCR_SetPixelRGB = SCR_SetPixelRGB16;
			SCR_GetPixelRGB = SCR_GetPixelRGB16;
			SCR_SetBoxRGB = SCR_SetBoxRGB16;
			SCR_SetBox = SCR_SetBoxRGB16;
			BOX_SetPixelRGB = BOX_SetPixelRGB16;
			BOX_GetPixelRGB = BOX_GetPixelRGB16;
			break;
		}
		case 3:
		{
			SCR_SetPixelRGB = SCR_SetPixelRGB24;
			SCR_GetPixelRGB = SCR_GetPixelRGB24;
			SCR_SetBoxRGB = SCR_SetBoxRGB24;
			SCR_SetBox = SCR_SetBoxRGB24;
			BOX_SetPixelRGB = BOX_SetPixelRGB24;
			BOX_GetPixelRGB = BOX_GetPixelRGB24;
			break;
		}
		case 4:
		{
			SCR_SetPixelRGB = SCR_SetPixelRGB32;
			SCR_GetPixelRGB = SCR_GetPixelRGB32;
			SCR_SetBoxRGB = SCR_SetBoxRGB32;
			SCR_SetBox = SCR_SetBoxRGBA;
			BOX_SetPixelRGB = BOX_SetPixelRGB32;
			BOX_GetPixelRGB = BOX_GetPixelRGB32;
			break;
		}
	}
	*/
}

void
MIC_Final(void)
{
	snd_pcm_hw_params_free(audio.mode.microphone.current);

	snd_pcm_close(audio.microphone);
}

/*
void
SCR_GetSize(int *width, int *height)
{
	*width = cp.video.mode.current.xres;
	*height = cp.video.mode.current.yres;
}

void
SCR_GetDepth(int *depth)
{
	*depth = cp.video.mode.current.bits_per_pixel >> 3;
}

void
SCR_Clear(void)
{
	memset(cp.video.screen, 0, cp.video.mode.fixed.smem_len);
}

void
SCR_Swap(void)
{
	memcpy(cp.video.screen, cp.video.swap, cp.video.mode.fixed.smem_len);
	//usleep(10000);
}

void
SCR_SetPalette(unsigned char pal[3][256])
{
	unsigned short fbpal[3][256];
	unsigned char c;
	for(c = 0; c < 256; c++)
	{
		fbpal[0][c] = pal[0][c];
		fbpal[1][c] = pal[1][c];
		fbpal[2][c] = pal[2][c];
	}
	cp.video.mode.palette.start = 0;
	cp.video.mode.palette.len = 256;
	cp.video.mode.palette.red = fbpal[0];
	cp.video.mode.palette.green = fbpal[1];
	cp.video.mode.palette.blue = fbpal[2];
	cp.video.mode.palette.transp = NULL;
	ioctl(cp.video.descriptor, FBIOPUTCMAP, &cp.video.mode.palette);
}
*/

void
MIC_ReadBuffer(char *buffer, unsigned int size)
{
	if((snd_pcm_readi(audio.microphone, buffer, size / 2)) != size / 2)
	{
		perror("Error: Unable to read from microphone");
		exit (1);
	}
}

/*
void
SCR_SetPixelColor(int x, int y, unsigned char c)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
 		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x) = c;
}

void
SCR_SetPixelRGB8(int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x) = (r >> 4) << 6 | (g >> 3) << 3 | b >> 3;
}

void
SCR_SetPixelRGB16(int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
		*(unsigned short *)(cp.video.screen + (y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3))) = (r << 11) | (g << 5) | (b);

}

void
SCR_SetPixelRGB24(int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
	{
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 0) = b;
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 1) = g;
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 2) = r;
	}
}

void
SCR_SetPixelRGB32(int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
	{
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 0) = b;
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 1) = g;
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 2) = r;
	}
}

void
SCR_SetPixelRGBA(int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
	{
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 0) = b;
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 1) = g;
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 2) = r;
		*(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 3) = a;
	}
}

void
SCR_GetPixelColor(int x, int y, unsigned char *c)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
 		*c = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x);
}

void
SCR_GetPixelRGB8(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
	{
		unsigned char c = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x);
		*r = ((c & 0xC0) >> 6) << 4;
		*g = ((c & 0x38) >> 3) << 3;
		*b = (c & 0x07) << 3;
	}
}

void
SCR_GetPixelRGB16(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
	{
		unsigned short p = *(unsigned short *)(cp.video.screen + (y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3)));
		*r = ((p & 0xF800) >> 11) << 3;
		*g = ((p & 0x07E0) >> 5) << 2;
		*b = (p & 0x001F) << 3;
	}
}

void
SCR_GetPixelRGB24(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
	{
		*b = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 0);
		*g = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 1);
		*r = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 2);
	}
}

void
SCR_GetPixelRGB32(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
	{
		*b = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 0);
		*g = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 1);
		*r = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 2);
	}
}

void
SCR_GetPixelRGBA(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a)
{
	if(0 <= x && x < cp.video.mode.current.xres && 0 <= y && y < cp.video.mode.current.yres)
	{
		*b = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 0);
		*g = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 1);
		*r = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 2);
		*a = *(cp.video.screen + y * cp.video.mode.fixed.line_length + x * (cp.video.mode.current.bits_per_pixel >> 3) + 3);
	}
}

*/
